package com.fish.web.interceptor;

import com.fish.common.annotation.RequiresPermission;
import com.fish.common.annotation.RequiresRole;
import com.fish.common.constant.JwtConstant;
import com.fish.common.exception.BusinessException;
import com.fish.common.result.ResultCode;
import com.fish.common.util.JwtUtil;
import com.fish.model.entity.Role;
import com.fish.service.MenuService;
import com.fish.service.RoleService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.List;
import java.util.Set;

/**
 * 权限拦截器
 */
@Slf4j
@Component
public class PermissionInterceptor implements HandlerInterceptor {
    
    @Autowired
    private MenuService menuService;
    
    @Autowired
    private RoleService roleService;
    
    @Autowired
    private com.fish.service.TokenService tokenService;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 只拦截Controller方法
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        
        // 检查方法级别的权限注解
        RequiresPermission methodPermission = handlerMethod.getMethodAnnotation(RequiresPermission.class);
        RequiresRole methodRole = handlerMethod.getMethodAnnotation(RequiresRole.class);
        
        // 检查类级别的权限注解
        RequiresPermission classPermission = handlerMethod.getBeanType().getAnnotation(RequiresPermission.class);
        RequiresRole classRole = handlerMethod.getBeanType().getAnnotation(RequiresRole.class);
        
        // 如果没有任何权限注解，直接放行
        if (methodPermission == null && methodRole == null && classPermission == null && classRole == null) {
            return true;
        }
        
        // 从请求头获取Token
        String token = request.getHeader(JwtConstant.TOKEN_HEADER);
        if (!StringUtils.hasText(token)) {
            throw new BusinessException(ResultCode.UNAUTHORIZED);
        }
        
        // 移除Bearer前缀
        if (token.startsWith(JwtConstant.TOKEN_PREFIX)) {
            token = token.substring(JwtConstant.TOKEN_PREFIX.length());
        }
        
        // 验证Token
        if (!JwtUtil.validateToken(token)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID);
        }
        
        // 检查Token是否在黑名单中
        if (tokenService.isInBlacklist(token)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID.getCode(), "Token已失效，请重新登录");
        }
        
        // 验证是否为Access Token
        if (!JwtUtil.isAccessToken(token)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID.getCode(), "请使用Access Token访问");
        }
        
        // 获取用户ID
        Long userId = JwtUtil.getUserId(token);
        
        // 校验角色
        if (methodRole != null) {
            checkRole(userId, methodRole.value());
        } else if (classRole != null) {
            checkRole(userId, classRole.value());
        }
        
        // 校验权限
        if (methodPermission != null) {
            checkPermission(userId, methodPermission.value());
        } else if (classPermission != null) {
            checkPermission(userId, classPermission.value());
        }
        
        return true;
    }
    
    /**
     * 校验角色
     */
    private void checkRole(Long userId, String roleKey) {
        List<Role> roles = roleService.getRolesByUserId(userId);
        boolean hasRole = roles.stream().anyMatch(role -> role.getRoleKey().equals(roleKey));
        
        if (!hasRole) {
            log.warn("用户[{}]没有角色[{}]权限", userId, roleKey);
            throw new BusinessException(ResultCode.FORBIDDEN);
        }
    }
    
    /**
     * 校验权限
     */
    private void checkPermission(Long userId, String permission) {
        Set<String> permissions = menuService.getPermissionsByUserId(userId);
        
        if (!permissions.contains(permission)) {
            log.warn("用户[{}]没有权限[{}]", userId, permission);
            throw new BusinessException(ResultCode.FORBIDDEN);
        }
    }
}